Spotify 2023: Análise das músicas mais populares

EDA
kaggle
R
Análise Descritiva
Autor

Enoque Filho

Data de Publicação

21 de dezembro de 2023

Introdução

Setup

Código
# pacotes = c('tidyverse', 'gt', 'reactable')
# enoqueR_dependencias = c("tidyverse", "gtsummary", "pryr", "rstatix", "moments")
# install.packages(c(pacotes, enoqueR_dependencias))
# remotes::install_github('enoqueR/enoqueR)

library(tidyverse)
library(enoqueR) 
library(gt)
library(reactable)

Conjunto de Dados

This dataset contains a comprehensive list of the most famous songs of 2023 as listed on Spotify. The dataset offers a wealth of features beyond what is typically available in similar datasets. It provides insights into each song’s attributes, popularity, and presence on various music platforms. The dataset includes information such as track name, artist(s) name, release date, Spotify playlists and charts, streaming statistics, Apple Music presence, Deezer presence, Shazam charts, and various audio features. - Fonte: https://www.kaggle.com/datasets/nelgiriyewithana/top-spotify-songs-2023

Código
# carregando o conjunto de dados
# disponivel em: https://www.kaggle.com/datasets/nelgiriyewithana/top-spotify-songs-2023

dados <- 
  readr::read_csv('spotify-2023.csv') %>% 
  janitor::clean_names()

dados %>% head(30)
Código
bind_rows(
  dados %>% enoqueR::overall_info(),
  dados %>% enoqueR::overall_tipos()
)

?(caption)

O conjunto de dados apresenta um total de 24 colunas, 955 observações e ausência de linhas duplicadas. Dentre as 24 colunas, 19 são numéricas e 5 são de caractere.

Código
dados %>% glimpse()
Rows: 953
Columns: 24
$ track_name               <chr> "Seven (feat. Latto) (Explicit Ver.)", "LALA"…
$ artist_s_name            <chr> "Latto, Jung Kook", "Myke Towers", "Olivia Ro…
$ artist_count             <dbl> 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, …
$ released_year            <dbl> 2023, 2023, 2023, 2019, 2023, 2023, 2023, 202…
$ released_month           <dbl> 7, 3, 6, 8, 5, 6, 3, 7, 5, 3, 4, 7, 1, 4, 3, …
$ released_day             <dbl> 14, 23, 30, 23, 18, 1, 16, 7, 15, 17, 17, 7, …
$ in_spotify_playlists     <dbl> 553, 1474, 1397, 7858, 3133, 2186, 3090, 714,…
$ in_spotify_charts        <dbl> 147, 48, 113, 100, 50, 91, 50, 43, 83, 44, 40…
$ streams                  <dbl> 141381703, 133716286, 140003974, 800840817, 3…
$ in_apple_playlists       <dbl> 43, 48, 94, 116, 84, 67, 34, 25, 60, 49, 41, …
$ in_apple_charts          <dbl> 263, 126, 207, 207, 133, 213, 222, 89, 210, 1…
$ in_deezer_playlists      <dbl> 45, 58, 91, 125, 87, 88, 43, 30, 48, 66, 54, …
$ in_deezer_charts         <dbl> 10, 14, 14, 12, 15, 17, 13, 13, 11, 13, 12, 5…
$ in_shazam_charts         <dbl> 826, 382, 949, 548, 425, 946, 418, 194, 953, …
$ bpm                      <dbl> 125, 92, 138, 170, 144, 141, 148, 100, 130, 1…
$ key                      <chr> "B", "C#", "F", "A", "A", "C#", "F", "F", "C#…
$ mode                     <chr> "Major", "Major", "Major", "Major", "Minor", …
$ danceability_percent     <dbl> 80, 71, 51, 55, 65, 92, 67, 67, 85, 81, 57, 7…
$ valence_percent          <dbl> 89, 61, 32, 58, 23, 66, 83, 26, 22, 56, 56, 5…
$ energy_percent           <dbl> 83, 74, 53, 72, 80, 58, 76, 71, 62, 48, 72, 8…
$ acousticness_percent     <dbl> 31, 7, 17, 11, 14, 19, 48, 37, 12, 21, 23, 18…
$ instrumentalness_percent <dbl> 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ liveness_percent         <dbl> 8, 10, 31, 11, 11, 8, 8, 11, 28, 8, 27, 15, 3…
$ speechiness_percent      <dbl> 4, 4, 6, 15, 6, 24, 3, 4, 9, 33, 5, 7, 7, 3, …
  • streams aparece como variável character apesar de apresentar observações numéricas e parece representar uma contagem

  • Uma inspeção nas observações da variável streams revelou uma observação contendo um possivel erro de nessa observação. Tal erro foi subtituido por um valor ausente e então os dados foram importados novamente.

Código
dados %>% 
  enoqueR::dataset_var_info() %>% 
  as_tibble() %>% 
  arrange(tipo, n_distinct) %>% 
  gt() %>% 
  fmt_number(columns = 6:7)
variavel tipo n n_miss n_distinct w p
mode character 953 0 2 NA NA
key character 858 95 12 NA NA
artist_s_name character 953 0 645 NA NA
track_name character 953 0 943 NA NA
artist_count numeric 953 0 8 0.64 0.00
released_month numeric 953 0 12 0.93 0.00
released_day numeric 953 0 31 0.94 0.00
in_deezer_charts numeric 953 0 34 0.50 0.00
instrumentalness_percent numeric 953 0 39 0.19 0.00
speechiness_percent numeric 953 0 48 0.71 0.00
released_year numeric 953 0 50 0.43 0.00
liveness_percent numeric 953 0 68 0.77 0.00
danceability_percent numeric 953 0 72 0.98 0.00
energy_percent numeric 953 0 80 0.98 0.00
in_spotify_charts numeric 953 0 82 0.67 0.00
valence_percent numeric 953 0 94 0.98 0.00
acousticness_percent numeric 953 0 98 0.87 0.00
bpm numeric 953 0 124 0.98 0.00
in_apple_charts numeric 953 0 172 0.88 0.00
in_shazam_charts numeric 903 50 199 0.41 0.00
in_apple_playlists numeric 953 0 234 0.72 0.00
in_deezer_playlists numeric 953 0 348 0.36 0.00
in_spotify_playlists numeric 953 0 879 0.62 0.00
streams numeric 952 1 949 0.76 0.00
  • Nenhuma das varíaveis numéricas apresenta distribuição normal.
  • Das 145 celulas vazias ?@tbl-overall 95 se encontram na coluna key e e 50 na coluna `in_shazam_charts.
  • A variável track_name não é suficiente para servir de nome para as observações (945 != 955).
  • As colunas track_name, artist_s_name e streamsapresentam valores distintos elevados. Deve ser buscar abordar tais colunas como caracteristica de denominação de cada observação.
  • As demais colunas de caractere (keye mode) podem ser consideradas fatores
  • colunas de data podem ser transformadas em uma coluna única
Código
dados = dados %>% 
  mutate(
    key = as.factor(key),
    mode = as.factor(mode),
    release_date = as_date(paste0(released_year,'-',released_month,'-',released_day))
  )

Análise Exploratória

Código
dados %>% 
  select(-release_date) %>% 
  variaveis() %>% 
  reactable::reactable(
     defaultColDef = colDef(
    format = colFormat(digits = 4))
    )

Análise visual univariada

Código
dados %>% 
  select(where(is.numeric)) %>% 
  pivot_longer(everything()) %>% 
    drop_na() %>% 
  ggplot(aes(x = value)) + 
  geom_histogram(color = 'white', fill = 'green4') + 
  facet_wrap(~name, scales = 'free') + 
  theme_test()

Código
dados %>% 
  select(where(is.numeric)) %>% 
  select(starts_with('in_'), contains('percent')) %>% 
  pivot_longer(everything()) %>% 
  mutate(tipo = ifelse(str_detect(name, 'percent'), 'song info', 'app info')) %>% 
  ggplot(aes(x = name, y = value)) +
  geom_boxplot(color = 'green4')  + 
  theme_test() + 
  facet_wrap(~tipo, scales = 'free', ncol = 1) + 
  coord_flip()

Código
# dados %>% 
#   select(where(is.factor)) %>% 
#   names() %>% 
#   map(.f = function(x){
#     tibble("{{x}}" := dados %>% pull({{x}})) %>% 
#   })
Código
dados %>% 
  mutate(key = factor(key, levels = c("C#", "D","D#","E","F","F#","G","G#","A","A#","B"))) %>% 
  select(where(is.factor)) %>% 
  pivot_longer(everything()) %>% 
  count(name, value) %>% 
  ggplot(aes(x = value, y = n)) + 
  geom_col(color = 'gray50', alpha = 0.5) +
  facet_wrap(~name, ncol = 2, scales ='free') + 
  theme_test()

Anláise bidimensional

Código
dados %>% 
  select(bpm, contains('percent'), starts_with('in')) %>% 
  drop_na() %>% 
  cor(method = 'spearman') %>% 
  reshape2::melt() %>% 
  ggplot(aes(x = Var2, y = Var1, fill = value, label = round(value, 2))) + 
  geom_tile() + 
  theme_minimal() + 
  scale_fill_gradient2(low = 'blue3', mid = 'lightyellow', high = 'red',midpoint = 0) + 
  theme(axis.text.x = element_text(angle = 90)) +
  labs(fill = 'Spearman') + 
  geom_text(color = 'black')

  • As variáveis relacionadas a contagem de presença das músicas em charts e playlists de diferentes serviços de streaming de música apresentaram correalações positivas que variam ao redor de 0.5 de correlação. in_deezer_playlists & in_spotify_playlists apresentaram a maior correlação positiva (0.84) e acousticness_percent & energy_percent a maior correlação negativa (-0.46).